/******************************************************************************
 * Copyright 2007 - 2021 Realtek Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/


#define _MLME_OSDEP_C_

#include <drv_types.h>
#include "rtw_wlan_config.h"

int32_t HdfWifiEventNewSta(const struct NetDevice *netDev, const uint8_t *macAddr, uint8_t addrLen,
    const struct StationInfo *info);

int32_t HdfWifiEventDelSta(struct NetDevice *netDev, const uint8_t *macAddr, uint8_t addrLen);

#ifdef RTK_DMP_PLATFORM
void Linkup_workitem_callback(struct work_struct *work)
{
	struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkup_workitem);
	_adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);

_func_enter_;

	RTW_INFO("+ Linkup_workitem_callback\n");

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
	kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKUP);
#else
	kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKUP);
#endif

_func_exit_;
}

void Linkdown_workitem_callback(struct work_struct *work)
{
	struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkdown_workitem);
	_adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);

_func_enter_;

	RTW_INFO("+ Linkdown_workitem_callback\n");

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12))
	kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKDOWN);
#else
	kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKDOWN);
#endif

_func_exit_;
}
#endif

void _rtw_join_timeout_handler (void *FunctionContext)
{
	_adapter *adapter = (_adapter *)FunctionContext;

	_cancel_timer_ex(&adapter->mlmepriv.assoc_timer);
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(adapter, rtw_join_timeout_handler, adapter);
#else
	rtw_join_timeout_handler(adapter);
#endif
}

void _rtw_scan_timeout_handler (void *FunctionContext)
{
	_adapter *adapter = (_adapter *)FunctionContext;

	_cancel_timer_ex(&adapter->mlmepriv.scan_to_timer);
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(adapter, rtw_scan_timeout_handler, adapter);
#else
	rtw_scan_timeout_handler(adapter);
#endif
}

#if 0
void _dynamic_check_timer_handlder (void *FunctionContext)
{
	_adapter *adapter = (_adapter *)FunctionContext;

    struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);

	_cancel_timer_ex(&pdvobj->dynamic_chk_timer);
	
#if (MP_DRIVER == 1)
	if (adapter->registrypriv.mp_mode == 1 && adapter->mppriv.mp_dm ==0) //for MP ODM dynamic Tx power tracking
	{
		_set_timer(&pdvobj->dynamic_chk_timer, 2000);
		return;
	}
#endif

#ifdef CONFIG_CONCURRENT_MODE
    _adapter *buddy_adapter = GET_ADAPTER(adapter, IFACE_ID1);
	if(buddy_adapter){
		#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
			rtw_run_in_thread_cmd(adapter, rtw_dynamic_check_timer_handlder, buddy_adapter);
		#else
			rtw_dynamic_check_timer_handlder(buddy_adapter);
		#endif
	}
#endif //CONFIG_CONCURRENT_MODE

#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(adapter, rtw_dynamic_check_timer_handlder, adapter);
#else
	rtw_dynamic_check_timer_handlder(adapter);
#endif		
	_set_timer(&pdvobj->dynamic_chk_timer, 2000);
}
#endif

#ifdef CONFIG_SET_SCAN_DENY_TIMER
void _rtw_set_scan_deny_timer_hdl(void *FunctionContext)
{
	_adapter *adapter = (_adapter *)FunctionContext;	 

	_cancel_timer_ex(&adapter->mlmepriv.set_scan_deny_timer);
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(adapter, rtw_set_scan_deny_timer_hdl, adapter);
#else
	rtw_set_scan_deny_timer_hdl(adapter);
#endif
}
#endif

/*
void rtw_init_mlme_timer(_adapter *padapter)
{
	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;

	rtw_init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, (timer_handler)rtw_join_timeout_handler, padapter);
	//rtw_init_timer(&(pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer), padapter->pnetdev, sitesurvey_ctrl_handler, padapter);
	rtw_init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, (timer_handler)_rtw_scan_timeout_handler, padapter);

	#ifdef CONFIG_DFS_MASTER
	rtw_init_timer(&(pmlmepriv->dfs_master_timer), padapter->pnetdev, (timer_handler)rtw_dfs_master_timer_hdl, padapter);
	#endif

	rtw_init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, (timer_handler)_dynamic_check_timer_handlder, padapter);
//	INIT_WORK(&(pmlmepriv->dynamic_chk_work), (work_func_t)_dynamic_check_work_handlder);

	#ifdef CONFIG_SET_SCAN_DENY_TIMER
	rtw_init_timer(&(pmlmepriv->set_scan_deny_timer), padapter->pnetdev, (timer_handler)_rtw_set_scan_deny_timer_hdl, padapter);
	#endif

#ifdef RTK_DMP_PLATFORM
	_init_workitem(&(pmlmepriv->Linkup_workitem), Linkup_workitem_callback, padapter);
	_init_workitem(&(pmlmepriv->Linkdown_workitem), Linkdown_workitem_callback, padapter);
#endif

}
*/

extern void rtw_indicate_wx_assoc_event(_adapter *padapter);
extern void rtw_indicate_wx_disassoc_event(_adapter *padapter, u16 reason);

void rtw_os_indicate_connect(_adapter *adapter)
{
	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);

#ifdef CONFIG_IOCTL_CFG80211
	if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==_TRUE ) || 
		(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==_TRUE ) )
	{
		rtw_cfg80211_ibss_indicate_connect(adapter);
	}
	else
		rtw_cfg80211_indicate_connect(adapter);
#endif //CONFIG_IOCTL_CFG80211

	rtw_indicate_wx_assoc_event(adapter);
	//netif_carrier_on(adapter->pnetdev);

	if(adapter->pid[2] !=0)
		rtw_signal_process(adapter->pid[2], SIGALRM);

#ifdef RTK_DMP_PLATFORM
	_set_workitem(&adapter->mlmepriv.Linkup_workitem);
#endif

}

extern void indicate_wx_scan_complete_event(_adapter *padapter);
extern void indicate_wx_scan_get_result_event(_adapter *padapter);

void rtw_os_indicate_scan_done( _adapter *padapter, bool aborted)
{
	indicate_wx_scan_get_result_event(padapter);
#ifdef CONFIG_IOCTL_CFG80211
	rtw_cfg80211_indicate_scan_done(padapter, aborted);
#endif

	indicate_wx_scan_complete_event(padapter);
}

static RT_PMKID_LIST   backupPMKIDList[ NUM_PMKID_CACHE ];
void rtw_reset_securitypriv( _adapter *adapter )
{
	u8	backupPMKIDIndex = 0;
	u8	backupTKIPCountermeasure = 0x00;
	u32	backupTKIPcountermeasure_time = 0;
	// add for CONFIG_IEEE80211W, none 11w also can use
	_irqL irqL;
	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
	
	_enter_critical_bh(&adapter->security_key_mutex, &irqL);
	
	if(adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)//802.1x
	{		 
		// Added by Albert 2009/02/18
		// We have to backup the PMK information for WiFi PMK Caching test item.
		//
		// Backup the btkip_countermeasure information.
		// When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds.

		_rtw_memset( &backupPMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );

		_rtw_memcpy( &backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
		backupPMKIDIndex = adapter->securitypriv.PMKIDIndex;
		backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure;
		backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time;		
#ifdef CONFIG_IEEE80211W
		//reset RX BIP packet number
		pmlmeext->mgnt_80211w_IPN_rx = 0;
#endif //CONFIG_IEEE80211W
		_rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof (struct security_priv));
		//rtw_init_timer(&(adapter->securitypriv.tkip_timer),adapter->pnetdev, rtw_use_tkipkey_handler, adapter);

		// Added by Albert 2009/02/18
		// Restore the PMK information to securitypriv structure for the following connection.
		_rtw_memcpy( &adapter->securitypriv.PMKIDList[ 0 ], &backupPMKIDList[ 0 ], sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
		adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
		adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure;
		adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time;		

		adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
		adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;

	}
	else //reset values in securitypriv 
	{
		//if(adapter->mlmepriv.fw_state & WIFI_STATION_STATE)
		//{
		struct security_priv *psec_priv=&adapter->securitypriv;

		psec_priv->dot11AuthAlgrthm =dot11AuthAlgrthm_Open;  //open system
		psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
		psec_priv->dot11PrivacyKeyIndex = 0;

		psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
		psec_priv->dot118021XGrpKeyid = 1;

		psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
		psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
		//}
	}
	// add for CONFIG_IEEE80211W, none 11w also can use
	_exit_critical_bh(&adapter->security_key_mutex, &irqL);

	RTW_INFO(FUNC_ADPT_FMT" - End to Disconnect\n", FUNC_ADPT_ARG(adapter));
}

void rtw_os_indicate_disconnect(_adapter *adapter,  u16 reason, u8 locally_generated)
{
	/* RT_PMKID_LIST   backupPMKIDList[NUM_PMKID_CACHE]; */

	rtw_netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */

#ifdef CONFIG_IOCTL_CFG80211
	rtw_cfg80211_indicate_disconnect(adapter,  reason, locally_generated);
#endif /* CONFIG_IOCTL_CFG80211 */

	rtw_indicate_wx_disassoc_event(adapter, reason);

#ifdef RTK_DMP_PLATFORM
	_set_workitem(&adapter->mlmepriv.Linkdown_workitem);
#endif
	/* modify for CONFIG_IEEE80211W, none 11w also can use the same command */
	rtw_reset_securitypriv_cmd(adapter);


}


void rtw_report_sec_ie(_adapter *adapter,u8 authmode,u8 *sec_ie)
{
}

void _rtw_dynamic_check_timer_handlder (void *FunctionContext)
{
	struct dvobj_priv *pdvobj = (struct dvobj_priv *)FunctionContext;

	_cancel_timer_ex(&(pdvobj->dynamic_chk_timer));
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(dvobj_get_primary_adapter(pdvobj), rtw_dynamic_check_timer_handlder, pdvobj);
#else
	rtw_dynamic_check_timer_handlder(pdvobj);
#endif	
}

void _rtw_reordering_ctrl_timeout_handler(void *pcontext)
{
	struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext;
    _adapter *padapter = preorder_ctrl->padapter;

	_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(padapter, rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
#else
	rtw_reordering_ctrl_timeout_handler(preorder_ctrl);
#endif	    
}

void _survey_timer_hdl (void *FunctionContext)
{
	_adapter *padapter = (_adapter *)FunctionContext;

	_cancel_timer_ex(&padapter->mlmeextpriv.survey_timer);
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(padapter, survey_timer_hdl, padapter);
#else
	survey_timer_hdl(padapter);
#endif	
}

void _link_timer_hdl (void *FunctionContext)
{
	_adapter *padapter = (_adapter *)FunctionContext;

	_cancel_timer_ex(&padapter->mlmeextpriv.link_timer);
#if CONFIG_DO_TIMER_CALLBACK_HANDLER_IN_THREAD
	rtw_run_in_thread_cmd(padapter, link_timer_hdl, padapter);
#else
	link_timer_hdl(padapter);
#endif	
}

void _addba_timer_hdl(void *FunctionContext)
{
	struct sta_info *psta = (struct sta_info *)FunctionContext;

	_cancel_timer_ex(&psta->addba_retry_timer);
	addba_timer_hdl(psta);
}

#ifdef CONFIG_IEEE80211W

void _sa_query_timer_hdl (void *FunctionContext)
{
	struct sta_info *psta = (struct sta_info *)FunctionContext;
	
	sa_query_timer_hdl(psta);
}

void init_dot11w_expire_timer(_adapter *padapter, struct sta_info *psta)
{
	rtw_init_timer(&psta->dot11w_expire_timer, padapter->pnetdev, (timer_handler)_sa_query_timer_hdl, psta);
}

#endif //CONFIG_IEEE80211W

void init_addba_retry_timer(_adapter *padapter, struct sta_info *psta)
{

	rtw_init_timer(&psta->addba_retry_timer, padapter->pnetdev, (timer_handler)_addba_timer_hdl, psta);
}

/*
void _reauth_timer_hdl(void *FunctionContext)
{
	_adapter *padapter = (_adapter *)FunctionContext;
	reauth_timer_hdl(padapter);
}

void _reassoc_timer_hdl(void *FunctionContext)
{
	_adapter *padapter = (_adapter *)FunctionContext;
	reassoc_timer_hdl(padapter);
}


void init_mlme_ext_timer(_adapter *padapter)
{	
	struct	mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;

	rtw_init_timer(&pmlmeext->survey_timer, padapter->pnetdev, (timer_handler)_survey_timer_hdl, padapter);
	rtw_init_timer(&pmlmeext->link_timer, padapter->pnetdev, (timer_handler)_link_timer_hdl, padapter);

	//rtw_init_timer(&pmlmeext->ADDBA_timer, padapter->pnetdev, _addba_timer_hdl, padapter);

	//rtw_init_timer(&pmlmeext->reauth_timer, padapter->pnetdev, _reauth_timer_hdl, padapter);
	//rtw_init_timer(&pmlmeext->reassoc_timer, padapter->pnetdev, _reassoc_timer_hdl, padapter);
}
*/

#ifdef CONFIG_AP_MODE

void rtw_indicate_sta_assoc_event(_adapter *padapter, struct sta_info *psta)
{
    union iwreq_data wrqu;
	struct sta_priv *pstapriv = &padapter->stapriv;
	struct net_device *netdev = padapter->pnetdev;
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);	
	struct rtk_StationInfo bstainfo;
	u8 *passoc_req = NULL;
	u32 assoc_req_len = 0;
	unsigned short		frame_type, ie_offset = 0;
	_irqL irqL;
	RTW_INFO("Enter rtw_indicate_sta_assoc_event \n");

	if(psta==NULL)
		return;

	if(psta->cmn.aid > NUM_STA)
		return;

	if(pstapriv->sta_aid[psta->cmn.aid - 1] != psta)
		return;
	
	RTW_INFO("+rtw_indicate_sta_assoc_event\n");
	
#ifndef CONFIG_IOCTL_CFG80211

#ifdef PLATFORM_HARMONY
	_enter_critical_bh(&psta->lock, &irqL);

	if (psta->passoc_req && psta->assoc_req_len > 0) {
		passoc_req = rtw_zmalloc(psta->assoc_req_len);
		if (passoc_req) {
			assoc_req_len = psta->assoc_req_len;
			_rtw_memcpy(passoc_req, psta->passoc_req, assoc_req_len);

			rtw_mfree(psta->passoc_req , psta->assoc_req_len);
			psta->passoc_req = NULL;
			psta->assoc_req_len = 0;
		}
	}
	_exit_critical_bh(&psta->lock, &irqL);

	if (passoc_req && assoc_req_len > 0) {
		frame_type = get_frame_sub_type(passoc_req);
		if (frame_type == WIFI_ASSOCREQ) {
			ie_offset = _ASOCREQ_IE_OFFSET_;
		} else { /* WIFI_REASSOCREQ */
			ie_offset = _REASOCREQ_IE_OFFSET_;
		}
		bstainfo.assocReqIes = passoc_req + IEEE80211_3ADDR_LEN+ie_offset;
		bstainfo.assocReqIesLen = assoc_req_len - IEEE80211_3ADDR_LEN - ie_offset;
		HdfWifiEventNewSta(netdev->dev,psta->cmn.mac_addr,ETH_ALEN,&bstainfo);
		rtw_mfree(passoc_req, assoc_req_len);
	}
	

#endif

#endif

}

void rtw_indicate_sta_disassoc_event(_adapter *padapter, struct sta_info *psta)
{
	struct sta_priv *pstapriv = &padapter->stapriv;
	struct net_device *netdev = padapter->pnetdev;

	RTW_INFO("Enter rtw_indicate_sta_disassoc_event \n");

	if(psta==NULL)
		return;

	if(psta->cmn.aid > NUM_STA)
		return;

	if(pstapriv->sta_aid[psta->cmn.aid - 1] != psta)
		return;
	
	RTW_INFO("+rtw_indicate_sta_disassoc_event\n");
	
#ifndef CONFIG_IOCTL_CFG80211
	HdfWifiEventDelSta(netdev->dev,psta->cmn.mac_addr,ETH_ALEN);
#endif
	
}


#ifdef CONFIG_HOSTAPD_MLME

static int mgnt_xmit_entry(struct sk_buff *skb, struct net_device *pnetdev)
{
	struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
	_adapter *padapter = (_adapter *)phostapdpriv->padapter;

	return rtw_hal_hostap_mgnt_xmit_entry(padapter, skb);
}

static int mgnt_netdev_open(struct net_device *pnetdev)
{
	struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);

	RTW_INFO("mgnt_netdev_open: MAC Address:" MAC_FMT "\n", MAC_ARG(pnetdev->dev_addr));


	init_usb_anchor(&phostapdpriv->anchored);
	
	rtw_netif_wake_queue(pnetdev);

	netif_carrier_on(pnetdev);
		
	//rtw_write16(phostapdpriv->padapter, 0x0116, 0x0100);//only excluding beacon 
		
	return 0;	
}
static int mgnt_netdev_close(struct net_device *pnetdev)
{
	struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);

	RTW_INFO("%s\n", __FUNCTION__);

	usb_kill_anchored_urbs(&phostapdpriv->anchored);

	netif_carrier_off(pnetdev);

	rtw_netif_stop_queue(pnetdev);

	//rtw_write16(phostapdpriv->padapter, 0x0116, 0x3f3f);
	
	return 0;	
}

#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29))
static const struct net_device_ops rtl871x_mgnt_netdev_ops = {
	.ndo_open = mgnt_netdev_open,
       .ndo_stop = mgnt_netdev_close,
       .ndo_start_xmit = mgnt_xmit_entry,
       //.ndo_set_mac_address = r871x_net_set_mac_address,
       //.ndo_get_stats = r871x_net_get_stats,
       //.ndo_do_ioctl = r871x_mp_ioctl,
};
#endif

int hostapd_mode_init(_adapter *padapter)
{
	unsigned char mac[ETH_ALEN];
	struct hostapd_priv *phostapdpriv;
	struct net_device *pnetdev;
	
	pnetdev = rtw_alloc_etherdev(sizeof(struct hostapd_priv));	
	if (!pnetdev)
	   return -ENOMEM;

	//SET_MODULE_OWNER(pnetdev);
       ether_setup(pnetdev);

	//pnetdev->type = ARPHRD_IEEE80211;
	
	phostapdpriv = rtw_netdev_priv(pnetdev);
	phostapdpriv->pmgnt_netdev = pnetdev;
	phostapdpriv->padapter= padapter;
	padapter->phostapdpriv = phostapdpriv;
	
	//pnetdev->init = NULL;
	
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,29))

	RTW_INFO("register rtl871x_mgnt_netdev_ops to netdev_ops\n");

	pnetdev->netdev_ops = &rtl871x_mgnt_netdev_ops;
	
#else

	pnetdev->open = mgnt_netdev_open;

	pnetdev->stop = mgnt_netdev_close;	
	
	pnetdev->hard_start_xmit = mgnt_xmit_entry;
	
	//pnetdev->set_mac_address = r871x_net_set_mac_address;
	
	//pnetdev->get_stats = r871x_net_get_stats;

	//pnetdev->do_ioctl = r871x_mp_ioctl;
	
#endif

	pnetdev->watchdog_timeo = HZ; /* 1 second timeout */	

	//pnetdev->wireless_handlers = NULL;

#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
	pnetdev->features |= NETIF_F_IP_CSUM;
#endif	

	
	
	if(dev_alloc_name(pnetdev,"mgnt.wlan%d") < 0)
	{
		RTW_INFO("hostapd_mode_init(): dev_alloc_name, fail! \n");		
	}


	//SET_NETDEV_DEV(pnetdev, pintfpriv->udev);


	mac[0]=0x00;
	mac[1]=0xe0;
	mac[2]=0x4c;
	mac[3]=0x87;
	mac[4]=0x11;
	mac[5]=0x12;
				
	_rtw_memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
	

	netif_carrier_off(pnetdev);


	/* Tell the network stack we exist */
	if (register_netdev(pnetdev) != 0)
	{
		RTW_INFO("hostapd_mode_init(): register_netdev fail!\n");
		
		if(pnetdev)
      		{	 
			rtw_free_netdev(pnetdev);
      		}
	}
	
	return 0;
	
}

void hostapd_mode_unload(_adapter *padapter)
{
	struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
	struct net_device *pnetdev = phostapdpriv->pmgnt_netdev;

	unregister_netdev(pnetdev);
	rtw_free_netdev(pnetdev);
	
}

#endif
#endif

